use crate::block::BLOCKS;
use std::fmt::{self, Display, Formatter};
// use log::info;

pub const MAPS: [[u8; 64]; 3] = [
    [
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0,
    ],
    [
        0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 1, 2, 0, 0, 4, 4,
        4, 4, 1, 2, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3,
        0, 0, 0, 0,
    ],
    [
        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 4, 1, 1, 0, 0, 0,
        5, 2, 4, 1, 1, 0, 0, 0, 5, 2, 4, 1, 1, 0, 0, 0, 5, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
        0, 0, 0, 0,
    ],
];

#[derive(Default, Debug, Clone)]
pub struct Map {
    pub grid: Vec<u8>,
    pub row: u8,
    pub col: u8,
    pub combo: u8,
    pub score: u32,
    pub collection: u32,
    pub hard_type: u8,
    pub hard_level: i8,
    pub clear_all_score: u32,
    pub full_rows: Vec<u8>,
    pub full_cols: Vec<u8>,
    pub full_updated: bool,
}

impl Display for Map {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let mut sd: String = "".to_owned();
        for i in 0..self.row {
            for j in 0..self.col {
                if self.grid[(j + i * self.col) as usize] != 0 {
                    sd.push_str("[]");
                } else {
                    sd.push_str(". ");
                }
            }
            sd.push_str("\n");
        }
        write!(
            f,
            "{}\nfullrows={:?}\nfullcols={:?}",
            sd, self.full_rows, self.full_cols
        )
    }
}

impl Map {
    pub fn new(r: u8, c: u8) -> Self {
        Self {
            grid: vec![],
            row: r,
            col: c,
            combo: 0,  // 连击次数
            score: 0,   // 当前分数
            collection: 0, // 收集物的数量
            hard_type: 0, // 0 不增加难度 1 按分数加难度 2 按收集物加难度
            hard_level: 0, // 设定难度等级，可以看成在stage中取值的偏移量，>0时将取更难的值
            clear_all_score: 0,
            full_rows: vec![],
            full_cols: vec![],
            full_updated: false,
        }
    }

    #[allow(dead_code)]
    pub fn set_grid(&mut self, data: &[u8]) {
        self.grid = data.iter().cloned().collect();
    }

    pub fn set_grid_byid(&mut self, id: usize) {
        self.grid = MAPS[id].iter().cloned().collect();
    }

    fn is_all_clear(&self) -> bool {
        for i in 0..self.row as usize {
            for j in 0..self.col as usize {
                let si = i * self.col as usize + j;
                if self.grid[si] != 0 {
                    return false;
                }
            }
        }
        true
    }

    pub fn put_down(&mut self, blkid: u8, x: u8, y: u8, only_test: bool) -> Result<bool, String> {
        let blk = &BLOCKS[blkid as usize - 1];
        if x > self.col - blk.rect.width as u8 || y > self.row - blk.rect.height as u8 {
            return Err(String::from("invaild pos"));
        }
        let mut bg = self.grid.clone();
        for i in 0..blk.rect.height as u8 {
            for j in 0..blk.rect.width as u8 {
                let gy = (i + blk.rect.y as u8) as usize;
                let gx = (j + blk.rect.x as u8) as usize;
                let sy = (y + i) as usize * self.col as usize;
                let sx = (x + j) as usize;
                if blk.grid[gy][gx] != 0 && self.grid[sy + sx] != 0 {
                    return Ok(false);
                }
                if blk.grid[gy][gx] != 0 {
                    bg[sy + sx] = blk.grid[gy][gx] * (blkid % 12 + 1);
                }
            }
        }
        if !only_test {
            self.grid = bg.clone();
        }
        Ok(true)
    }

    pub fn can_put_block(&mut self, blkid: u8) -> bool {
        let rc = self.row - BLOCKS[blkid as usize - 1].rect.height as u8 + 1;
        let cc = self.col - BLOCKS[blkid as usize - 1].rect.width as u8 + 1;

        for m in 0..rc {
            for n in 0..cc {
                if self.put_down(blkid, n, m, true).unwrap() {
                    return true;
                }
            }
        }
        false
    }

    pub fn calc_full(&mut self) {
        self.full_updated = false;
        self.full_rows.clear();
        self.full_cols.clear();
        for i in 0..self.row as usize {
            let mut full = true;
            for j in 0..self.col as usize {
                let si = i * self.col as usize + j;
                if self.grid[si] == 0 {
                    full = false;
                    break;
                }
            }
            if full {
                self.full_rows.push(i as u8);
            }
        }
        for i in 0..self.col as usize {
            let mut full = true;
            for j in 0..self.row as usize {
                let si = j * self.col as usize + i;
                if self.grid[si] == 0 {
                    full = false;
                    break;
                }
            }
            if full {
                self.full_cols.push(i as u8);
            }
        }
        self.full_updated = true;
    }

    // 第一个返回值: 是否全消1表示全消，0表示非全消
    // 第二个返回值: 消除行列总值
    pub fn clear_full(&mut self) -> (u8, u8){
        let mut allc = 0u8;
        let crc;

        if !self.full_updated {
            self.calc_full();
        }
        crc = self.full_cols.len() as u8 + self.full_rows.len() as u8;
        for r in &self.full_rows {
            for i in 0..self.col as usize {
                let si = *r as usize * self.col as usize + i;
                self.grid[si] = 0;
            }
        }
        for c in &self.full_cols {
            for i in 0..self.row as usize {
                let si = i * self.col as usize + *c as usize;
                self.grid[si] = 0;
            }
        }
        self.full_rows.clear();
        self.full_cols.clear();
        if self.is_all_clear() {
            allc = 1u8;
            self.clear_all_score = self.score;
        }
        (allc, crc)
    }
}
